﻿namespace Reap.AzureResource.API.Controllers {
	using System;
	using System.Collections.Generic;
	using System.Configuration;
	using System.Diagnostics;
	using System.IO;
	using System.Linq;
	using System.Net;
	using System.Net.Http;
	using System.Net.Http.Headers;
	using System.Threading.Tasks;
	using System.Web;
	using System.Web.Http;

	using Reap.AzureResource.Model.Models;
	using Reap.AzureResource.Service;
	using Reap.EmailServer;

	public class ResourceController:ApiController {

		private IResourceService resourceService;

		private IResourceActivityService resourceActivityService;

		private ILocationService locationService;
		#region Constructors and Destructors

		public ResourceController(ILocationService locationService,IResourceService resourceService,IResourceActivityService resourceActivityService) {
			this.FileProvider = new FileProvider();
			this.resourceService = resourceService;
			this.resourceActivityService = resourceActivityService;
			this.locationService = locationService;
		}

		#endregion

		#region Public Properties

		public IFileProvider FileProvider { get; set; }

		#endregion

		#region Public Methods and Operators
	
		[HttpGet]
		[Route("api/get")]
		public HttpResponseMessage GetFileAsync(int id) {
			var resouce = resourceService.GetResourceById(id);
			if(resouce == null)
				return null;

			FileStream fileStream = this.FileProvider.Open(resouce.ResourcePath);
			var response = new HttpResponseMessage();
			response.Content = new StreamContent(fileStream);
			response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
			response.Content.Headers.ContentDisposition.FileName = resouce.ResourceName;
			response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
			response.Content.Headers.ContentLength = this.FileProvider.GetLength(resouce.ResourcePath);
			ResourceActivity resourceActivity = new ResourceActivity();
			resourceActivity.ActivityDate = DateTime.Now;
			resourceActivity.ResourceId = id;
			resourceActivityService.AddResouceActivity(resourceActivity);
			return response;
		}
		static String BytesToString(long byteCount) {
			string[] suf = { "B","KB","MB","GB","TB","PB","EB" }; //Longs run out around EB
			if(byteCount == 0)
				return "0" + suf[0];
			long bytes = Math.Abs(byteCount);
			int place = Convert.ToInt32(Math.Floor(Math.Log(bytes,1024)));
			double num = Math.Round(bytes / Math.Pow(1024,place),1);
			return (Math.Sign(byteCount) * num) + suf[place];
		}
		[HttpPost]
		[Route("api/upload")]
		public async Task<int> PostFormData() {
			// Check if the request contains multipart/form-data.
			if(!Request.Content.IsMimeMultipartContent()) {
				throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
			}
			DateTime starTime = DateTime.Now;
			string root = HttpContext.Current.Server.MapPath("~/Uploads/");
			MyStreamProvider streamProvider = new MyStreamProvider(root);
			//var provider = new MultipartFormDataStreamProvider(root);

			try {
				// Read the form data.
				await Request.Content.ReadAsMultipartAsync(streamProvider);

				// This illustrates how to get the file names.
				//foreach(MultipartFileData file in streamProvider.FileData) {
				//	Trace.WriteLine(file.Headers.ContentDisposition.Size);
				//	Trace.WriteLine("Server file path: " + file.LocalFileName);
				//}
				FileInfo fileInfo = new FileInfo(streamProvider.FileData[0].LocalFileName);

				Resource resource = new Resource();
				DateTime endTime = DateTime.Now;
				resource.FileSize = BytesToString(fileInfo.Length);
				resource.ResourceName = streamProvider.OriginalName;
				resource.ResourcePath = streamProvider.NewName;
				resource.UploadStartTime = starTime;
				resource.UploadEndTime = endTime;
				resource.Fstatus = 0;
				resourceService.AddResource(resource);

				return resource.Id;
			} catch(System.Exception e) {
				throw e;
			}
		}
		//public int Upload() {
		//	DateTime starTime = DateTime.Now;
		//	int result = 0;
		//	HttpRequest httpRequest = HttpContext.Current.Request;
		//	if(HttpContext.Current.Request.Files.AllKeys.Any()) {
		//		Resource resource = new Resource();


		//		HttpPostedFile postedFile = httpRequest.Files[0];

		//		string fileDir = HttpContext.Current.Server.MapPath("~/Uploads/");

		//		string ext = Path.GetExtension(postedFile.FileName);
		//		string newName = Guid.NewGuid() + ext;

		//		postedFile.SaveAs(Path.Combine(fileDir,newName));
		//		DateTime endTime = DateTime.Now;
		//		resource.FileSize = BytesToString(postedFile.ContentLength);
		//		resource.ResourceName = postedFile.FileName;
		//		resource.ResourcePath = newName;
		//		resource.UploadStartTime = starTime;
		//		resource.UploadEndTime = endTime;
		//		resource.Fstatus = 0;
		//		resourceService.AddResource(resource);
		//		result = resource.Id;
		//	}

		//	return result;

		//}
		[HttpGet]
		[Route("api/updateTask")]
		public async Task<int> UpdateTask(int id) {
			HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin","*");
			try {
				var resource = resourceService.GetResourceById(id);
				resource.Fstatus = 1;
				resourceService.UpdateResource(resource);
				//判断外网还是内网
				if(resource.LocationId != null) {
					var location = locationService.GetLocationById(( int )resource.LocationId);
					if(location == null) {
						return 1;
					}
					var s = location.FUrl ?? "10.1.1.46";
					if(location.FtypeID == 0)
						return 1;
					const string Subject = "文件下载通知";
					var body = "<p>提示：请及时下载文件：<a href=\""+s+"/api/get/?id=" + resource.Id + "\" target='_blank'>点击下载文件</a>，文件有效期默认为2小时！<p>";
					body += "<p>温馨提示：该邮件为提醒邮件，请勿回复！<p>";
					var toMail = new Dictionary<string,string> { { location.Fmail,location.FuserName } };
					await EmailHelper.SendMail(toMail,new Dictionary<string,string>(),body,Subject);
					resource.Fstatus = 2;
					resourceService.UpdateResource(resource);
				}

				return 1;
			} catch {
				return 0;
			}

		}
		#endregion
	}
	public class MyStreamProvider:MultipartFormDataStreamProvider {
		public MyStreamProvider(string uploadPath)
			: base(uploadPath) {

		}

		public string OriginalName { get; set; }
		public string NewName { get; set; }


		public override string GetLocalFileName(HttpContentHeaders headers) {
			var fileName = headers.ContentDisposition.FileName;
			if(string.IsNullOrWhiteSpace(fileName)) {
				fileName = Guid.NewGuid() + ".data";
			}

			if(fileName.StartsWith(@"""") && fileName.EndsWith(@""""))
				fileName = fileName.Substring(1,fileName.Length - 2);

			OriginalName = fileName;
			var extension = Path.GetExtension(fileName);
			fileName = Guid.NewGuid() + extension;
			fileName = fileName.Replace("\"",string.Empty);
			NewName = fileName;
			return fileName;
		}
	}
	public interface IFileProvider {
		#region Public Methods and Operators

		bool Exists(string name);

		long GetLength(string name);

		FileStream Open(string name);

		#endregion
	}

	public class FileProvider:IFileProvider {
		#region Constants

		private const string AppSettingsKey = "FileProvider.FilesLocation";

		private const string DefaultFileLocation = "~/uploads";

		#endregion

		#region Fields

		private readonly string filesDirectory;

		#endregion

		#region Constructors and Destructors

		public FileProvider() {
			this.filesDirectory = DefaultFileLocation;
			string fileLocation = ConfigurationManager.AppSettings[AppSettingsKey];
			if(!String.IsNullOrWhiteSpace(fileLocation)) {
				this.filesDirectory = fileLocation;
			}
		}

		#endregion

		#region Public Methods and Operators

		public bool Exists(string name) {
			//make sure we dont access directories outside of our store for security reasons
			string file = Directory.GetFiles(this.filesDirectory,name,SearchOption.TopDirectoryOnly).FirstOrDefault();
			return file != null;
		}

		public long GetLength(string name) {
			return new FileInfo(this.GetFilePath(name)).Length;
		}

		public FileStream Open(string name) {
			return File.Open(this.GetFilePath(name),FileMode.Open,FileAccess.Read);
		}

		#endregion

		#region Methods

		private string GetFilePath(string name) {
			return HttpContext.Current.Server.MapPath(Path.Combine(this.filesDirectory,name));
		}

		#endregion
	}
}